package com.example.mallorder.config;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class FilePersistence implements InitFunc {

  @Override
  public void init() throws Exception {
    // 地址可以自己定义
    String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + "mall-order";
    String flowRulePath = ruleDir + "/flow-rule.json";
    String degradeRulePath = ruleDir + "/degrade-rule.json";
    String systemRulePath = ruleDir + "/system-rule.json";
    String authorityRulePath = ruleDir + "/authority-rule.json";
    String paramFlowRulePath = ruleDir + "/param-flow-rule.json";

    this.mkdirIfNotExits(ruleDir);
    this.createFileIfNotExits(flowRulePath);
    this.createFileIfNotExits(degradeRulePath);
    this.createFileIfNotExits(systemRulePath);
    this.createFileIfNotExits(authorityRulePath);
    this.createFileIfNotExits(paramFlowRulePath);

    // 流控规则
    ReadableDataSource<String, List<FlowRule>> flowRuleRDS =
        new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
    FlowRuleManager.register2Property(flowRuleRDS.getProperty());
    WritableDataSource<List<FlowRule>> flowRuleWDS =
        new FileWritableDataSource<>(flowRulePath, this::encodeJson);
    WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);

    // 降级规则
    ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS =
        new FileRefreshableDataSource<>(degradeRulePath, degradeRuleListParser);
    DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
    WritableDataSource<List<DegradeRule>> degradeRuleWDS =
        new FileWritableDataSource<>(degradeRulePath, this::encodeJson);
    WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);

    // 系统规则
    ReadableDataSource<String, List<SystemRule>> systemRuleRDS =
        new FileRefreshableDataSource<>(systemRulePath, systemRuleListParser);
    SystemRuleManager.register2Property(systemRuleRDS.getProperty());
    WritableDataSource<List<SystemRule>> systemRuleWDS =
        new FileWritableDataSource<>(systemRulePath, this::encodeJson);
    WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);

    // 授权规则
    ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS =
        new FileRefreshableDataSource<>(authorityRulePath, authorityRuleListParser);
    AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
    WritableDataSource<List<AuthorityRule>> authorityRuleWDS =
        new FileWritableDataSource<>(authorityRulePath, this::encodeJson);
    WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);

    // 热点参数规则
    ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS =
        new FileRefreshableDataSource<>(paramFlowRulePath, paramFlowRuleListParser);
    ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
    WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS =
        new FileWritableDataSource<>(paramFlowRulePath, this::encodeJson);
    ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
  }

  private Converter<String, List<FlowRule>> flowRuleListParser =
      source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
  private Converter<String, List<DegradeRule>> degradeRuleListParser =
      source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {});
  private Converter<String, List<SystemRule>> systemRuleListParser =
      source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {});

  private Converter<String, List<AuthorityRule>> authorityRuleListParser =
      source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {});

  private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser =
      source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {});

  private void mkdirIfNotExits(String filePath) throws IOException {
    File file = new File(filePath);
    if (!file.exists()) {
      file.mkdirs();
    }
  }

  private void createFileIfNotExits(String filePath) throws IOException {
    File file = new File(filePath);
    if (!file.exists()) {
      file.createNewFile();
    }
  }

  private <T> String encodeJson(T t) {
    return JSON.toJSONString(t);
  }
}
